package com.jay.example.IndoorPositioningSystem;

/****
 * https://gitee.com/unw1900/Indoor_Positioning_System
 * 动画显示需要优化，现只是“暴力”实现。
 * 扫描到第一个Beacon后，location才会在界面正常显示。
 * 整个项目没有清除测试代码。
 */
import android.Manifest;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.annotation.SuppressLint;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothManager;
import android.bluetooth.le.BluetoothLeScanner;
import android.bluetooth.le.ScanCallback;
import android.bluetooth.le.ScanResult;
import android.bluetooth.le.ScanSettings;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.graphics.Canvas;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.SystemClock;
import android.support.annotation.RequiresApi;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.content.LocalBroadcastManager;
import android.support.v7.app.AppCompatActivity;
import android.text.method.ScrollingMovementMethod;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.RotateAnimation;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;

import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Objects;

/***
 * 已将 DeviceScanActivity.java 内的功能整合到 MainActivity.java中
 */
public class MainActivity extends AppCompatActivity
        implements SensorEventListener, View.OnTouchListener {

    public static final String TAG = "MainActivity";
    public static final String ARG_SECTION_NUMBER = "section_number";

    private TextView tv_value1,tv_value2,tv_value3;
    private TextView tv_value4,tv_value5,tv_value6;
    private TextView tv_value7,tv_value8;
    private TextView Ble_ID;
    /*********  动画  **************/
    private ImageView compass;
    private ImageView arrow;
    private ImageView location;
    private float location_Y;
    private float location_X;
    float[] moveArrow = new float[2];//箭头位置
    private float currentDegree = 0f; //记录指南针转过的角度
    private RelativeLayout touchLayout;
    private ImageView mapCompass;
    private float screenMove;
    /**********  传感器   ************/
    private SensorManager sSensorManager;
    private Sensor mLinearAcceleration,mSensorOrientation;
    /*******   滤波  ************/
    private int accNum = 0;
    private int degreeNum = 0;
    private int degreeLength = 5;
    float degree = 0;
    float[] degreeBuf = new float[degreeLength];
    MovingAverage movingAverage;
    /******* 步伐检测 *******/
     StepDetector stepDetector;
    /*******  时间  **********/
    Calendar calendar;
    private boolean flagOfTime;
    private long beginTime;//活动开始时间
    private long diffTime;//活动运行时间
    /********  广播  **********/
    private LocalReceiver localReceiver;
    private LocalBroadcastManager localBroadcastManager;
    /********   图表  **********/
    private RealtimeUpdates realTimeGraph;
    Canvas mycanvas;
    MyView myView;
    /********   步伐   *********/
    private short stepSum = 0;
    private float stepSize = 65;//cm
    /*******   设备扫描    ******/
    public StringBuffer beaconList = new StringBuffer();
    Beacon myBeacon;
    int lastBeacon = 0;
    private ScanSettings mScannerSetting;
    private Kalman kalman_1,kalman_2,kalman_3,kalman_4;
//    float[][] Beacon_XY;//设备坐标
    boolean resetLocationFlag = true;
    private float sumD = 0; //行走距离测试


    @Override
    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);
        LayoutInit();//初始化UI界面
        SysInit();
        initBLE();
        iBeacon();
        intiKalmanFilter();
        getBlePermissionFromSys();
        //mSensorOrientation= sSensorManager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR);//旋转矢量
        //sManager.registerListener(this, mSensorRotationVector,SensorManager.SENSOR_DELAY_UI);
        bindViews();
        myView = (MyView) findViewById(R.id.paintView);

        Button StartScan = (Button) findViewById(R.id.startScan);
        StartScan.setOnClickListener(new View.OnClickListener() {
            @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
            @Override
            public void onClick(View v) {
                Log.d("Button", "Click Button!");
                mScannerSetting = new ScanSettings.Builder()
                        //退到后台时设置扫描模式为高频率
                        .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
                        .build();
                scanLeDevice(true);
                Toast.makeText(MainActivity.this,
                        "Start BLE Scan",Toast.LENGTH_SHORT).show();
            }
        });

    }

    /**
     * 初始化 UI 界面
     */
    @SuppressLint("ClickableViewAccessibility")
    private void LayoutInit(){
        setContentView(R.layout.activity_main);
        compass = (ImageView) findViewById(R.id.compass);
        arrow = (ImageView) findViewById(R.id.arrow);
        arrow.bringToFront();
        location = (ImageView) findViewById(R.id.location);
        location.bringToFront();
        touchLayout = (RelativeLayout) findViewById(R.id.reLayout);
        touchLayout.setOnTouchListener(this);
        mapCompass = (ImageView) findViewById(R.id.compass_map);
        mapCompass.bringToFront();

        addFragment(new RealtimeUpdates());
    }

    /**
     * 初始化需要的各类功能：1.Intent，
     *                       2.sensor，
     *                       3.stepDetector
     *                       4.movingAverage
     */
    private void SysInit(){
        localBroadcastManager = LocalBroadcastManager.getInstance(this); // 获取本地广播实例
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction("com.MaiActivity.LOCAL_BROADCAST");
        localReceiver = new LocalReceiver();
        localBroadcastManager.registerReceiver(localReceiver, intentFilter); // 注册本地广播监听器

        sSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE); //获取传感器管理器
        movingAverage = new MovingAverage();//获取滤波器
        stepDetector = new StepDetector();


    }

    /**
     * 注册监听器、光标位置、获取calendar与fragment实例
     */
    @Override
        protected void onResume() {
        super.onResume();
        //注册监听器
        if (sSensorManager != null) {//线性加速度
            mLinearAcceleration = sSensorManager.getDefaultSensor(Sensor.TYPE_LINEAR_ACCELERATION);
        }else {
            Log.d(TAG,"sManager.getDefaultSensor = false! ");
        }
        sSensorManager.registerListener(this, mLinearAcceleration,
                SensorManager.SENSOR_DELAY_GAME);//50hz(game),应滤波后显示

        sSensorManager.registerListener(this,//方向传感器
                sSensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION),
                SensorManager.SENSOR_DELAY_GAME);

        realTimeGraph = (RealtimeUpdates) getSupportFragmentManager()//获取fragment实例
                .findFragmentById(R.id.fragment);
        calendar = Calendar.getInstance();//获取时间日期实例

        moveArrow[0] = myView.getLastStepX();
        moveArrow[1] = myView.getLastStepY();
        /****** 初始化定位图标 **********/

//        ObjectAnimator movingX = ObjectAnimator.ofFloat(arrow,"translationX",moveArrow[0]-12);//箭头大小：25dp
//        ObjectAnimator movingY = ObjectAnimator.ofFloat(arrow,"translationY",moveArrow[1]+18);
        ObjectAnimator movingX = ObjectAnimator.ofFloat(arrow,"translationX",moveArrow[0]-100);
        ObjectAnimator movingY = ObjectAnimator.ofFloat(arrow,"translationY",moveArrow[1]-60);
        AnimatorSet animatorSet = new AnimatorSet();
        animatorSet.play(movingY).with(movingX);
        animatorSet.setDuration(1000);
        animatorSet.start();

        ObjectAnimator movingLocationX = ObjectAnimator.ofFloat(location,"translationX",0);
        ObjectAnimator movingLocationY = ObjectAnimator.ofFloat(location,"translationY",0);
        AnimatorSet animatorLocation = new AnimatorSet();
        animatorLocation.play(movingLocationX).with(movingLocationY);
        animatorLocation.setDuration(1000);
        animatorLocation.start();

//        myView.mPaintD.reset();
//        myView.setDestination(0,0);

    }

    @Override
    protected void onPause() {
        super.onPause();
        // 取消注册
        sSensorManager.unregisterListener(this);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
//        unregisterReceiver(networkChangeReceiver);
        localBroadcastManager.unregisterReceiver(localReceiver);
    }

    /**
     * UI 显示文本初始化
     */
    private void bindViews() {
//        tv_value1 = (TextView) findViewById(R.id.tv_value1);
//        tv_value2 = (TextView) findViewById(R.id.tv_value2);
//        tv_value3 = (TextView) findViewById(R.id.tv_value3);
        tv_value4 = (TextView) findViewById(R.id.tv_value4);
        tv_value5 = (TextView) findViewById(R.id.tv_value5);
        Ble_ID = (TextView) findViewById(R.id.tv_value7);
        tv_value6 = (TextView) findViewById(R.id.tv_value6);

//        tv_value7 = (TextView) findViewById(R.id.tv_value7);
//        tv_value8 = (TextView) findViewById(R.id.tv_value8);
    }

    /**
     * 当传感器接收到数据时回调
     * 记录传感器类型、数据以及时间（时间转换）
     * 将数据传入相应的模块进一步处理
     * @param event 传感器数据信息
     */
    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR1)
    @SuppressLint({"SetTextI18n", "SimpleDateFormat"})
    @Override
    public void onSensorChanged(SensorEvent event)
    {
        if (!flagOfTime) {//记录开始时间
            beginTime = System.currentTimeMillis() +
                    ((event.timestamp - SystemClock.elapsedRealtimeNanos()) / 100000000L);
            flagOfTime = true;
        }
        if (event.sensor.getType() == Sensor.TYPE_LINEAR_ACCELERATION) {//线性加速度
            diffTime = getTime(event.timestamp);//获得相对时间戳

            float x = event.values[0];
            float y = event.values[1];
            float z = event.values[2];
            double acc = Math.sqrt(Math.pow(x,2) + Math.pow(y,2) + Math.pow(z,2));
            double accout = movingAverage.movingAverageFilter(acc);
            realTimeGraph.getdata(accout,diffTime);//获取原始Acc数据并绘制
//            realTimeGraph.getfilterdata(accout,diffTime);//获取经过滤波的Acc数据并绘制
//            tv_value1.setText("X：" + (float) (Math.round(x * 100)) / 100);
//            tv_value2.setText("Y：" + (float) (Math.round(y * 100)) / 100);
//            tv_value3.setText("Z：" + (float) (Math.round(z * 100)) / 100);
            //以秒为单位在UI显示运行时间，并以 时：分：秒：毫秒 的形式显示时间
//            tv_value4.setText("CurrentTime："+ new SimpleDateFormat("hh:mm:ss").
//                    format(calendar.getTime())+"    " +
//                    "Runtime："+ Math.round(diffTime *0.001) + "s");
            tv_value4.setText("CurrentTime："+ new SimpleDateFormat("hh:mm:ss").
                    format(calendar.getTime())+" ");
            /** 步伐探测  **/
            if(stepDetector.StepDetector(accout, diffTime *0.001)){//步伐检测,
                stepSum++;//检测到步伐则加一

//                tv_value6.setText("总步数：" + stepSum + "\n");
                float[] addArrowMoving = myView.addStep(currentDegree,
                        (float) ((stepDetector.getCompensator())*stepSize));//更新当前位置

                sumD += (float) ((stepDetector.getCompensator())*stepSize);
                tv_value6.setText("距离："+ sumD/100 + "m");
                screenMove = myView.screenMove();//屏幕中心是否需要偏移
                myView.invalidate();
                if (screenMove < 0) {//移动屏幕
                    ObjectAnimator movingX = ObjectAnimator.ofFloat(arrow, "translationX",
                            moveArrow[0]-100 - screenMove, moveArrow[0]-100 + addArrowMoving[0] - screenMove);
                    ObjectAnimator movingY = ObjectAnimator.ofFloat(arrow, "translationY",
                            moveArrow[1]-60, moveArrow[1]-60 + addArrowMoving[1]);
                    AnimatorSet animatorSet = new AnimatorSet();
                    animatorSet.play(movingX).with(movingY);
                    animatorSet.setDuration(700);
                    animatorSet.start();

                    ObjectAnimator movingLocation_X = ObjectAnimator.ofFloat(location,"translationX",
                            location_X - addArrowMoving[0]);
                    Log.d(TAG,"location: "+(location_X-addArrowMoving[0]));
                    ObjectAnimator movingLocation_Y = ObjectAnimator.ofFloat(location,"translationY",
                            location_Y);
                    AnimatorSet animatorSetLocation = new AnimatorSet();
                    animatorSetLocation.play(movingLocation_Y).with(movingLocation_X);
                    animatorSetLocation.setDuration(1);
                    animatorSetLocation.start();
                    location_X -= addArrowMoving[0];
                }else {//不移动屏幕
                    ObjectAnimator movingX = ObjectAnimator.ofFloat(arrow, "translationX",
                            moveArrow[0]-100, moveArrow[0]-100 + addArrowMoving[0]);
                    ObjectAnimator movingY = ObjectAnimator.ofFloat(arrow, "translationY",
                            moveArrow[1]-60, moveArrow[1]-60 + addArrowMoving[1]);
                    AnimatorSet animatorSet = new AnimatorSet();
                    animatorSet.play(movingX).with(movingY);
                    animatorSet.setDuration(700);
                    animatorSet.start();
                }
//                ObjectAnimator movingX = ObjectAnimator.ofFloat(arrow,"translationX",moveArrow[0]-40,moveArrow[0]+moveArrow[2]-40);//箭头大小：25dp
//                ObjectAnimator movingY = ObjectAnimator.ofFloat(arrow,"translationY",moveArrow[1]-9,moveArrow[1]+moveArrow[3]-9);
//                AnimatorSet animatorSet = new AnimatorSet();
//                animatorSet.play(movingX).with(movingY);
//                animatorSet.setDuration(700);
//                animatorSet.start();
                moveArrow[0] = moveArrow[0] + addArrowMoving[0];
                moveArrow[1] = moveArrow[1] + addArrowMoving[1];


            }
        }
//        if (event.sensor.getType() == Sensor.TYPE_ROTATION_VECTOR){       //旋转矢量
//            tv_value6.setText("沿 z 轴的旋转矢量分量 z * sin(θ/2)" +  event.values[0]);
//        }
        if (event.sensor.getType() == Sensor.TYPE_ORIENTATION) {//方向

            float degree = movingAverage.movingAverageFilter(event.values[0]); // 获取绕Z轴转过的角度
            /*****    绘制      *****/
//            realTimeGraph.getDegree(-currentDegree, diffTime);//绘制航向角变化

            ObjectAnimator moving = ObjectAnimator.ofFloat(arrow,"rotation",-currentDegree-180,-degree-180);//行人朝向,+25
            moving.setDuration(200);
            moving.start();
            // 创建旋转动画（反向转过degree度）
            RotateAnimation ra = new RotateAnimation(currentDegree, -degree,
                    Animation.RELATIVE_TO_SELF, 0.5f,
                    Animation.RELATIVE_TO_SELF, 0.5f);
            ra.setDuration(200); // 设置动画的持续时间
            ra.setFillAfter(true); // 设置动画结束后的保留状态
            compass.startAnimation(ra);// 启动动画
            currentDegree = -degree;//负号不可取消，否则引入计算问题
            tv_value5.setText("航向角：" + Math.round(-currentDegree)+"°   "+"总步数：" + stepSum + "\n");//显示时符号修正
//            tv_value7.setText("Max = " );
//            tv_value8.setText("Min = ");
//            realTimeGraph.getDegree(-currentDegree, diffTime);//绘制航向角变化
        }
    }

    /****
     * 传感器精度变化时调用
     * @param sensor 传感器类型
     * @param accuracy 传感器新精度
     */
    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy) {}

    /****
     *  在主界面添加Fragment用以显示图表
     * @param fragment 片段
     */
    private void addFragment(Fragment fragment) {
        FragmentManager fragmentManager = getSupportFragmentManager();
        FragmentTransaction transaction = fragmentManager.beginTransaction();   // 开启一个事务
        transaction.add(R.id.fragment, fragment);
        transaction.commit();
    }

    /****
     * 计算数据时间戳：基于程序运行时间（ns）
     * @param eventTime 传感器检测到数据的时间（以设备boot时间为基准）
     * @return 传感器检测到数据的时间（以本程序运行时间为基准）
     */
    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR1)
    private long getTime(long eventTime){
        long time = System.currentTimeMillis() +
                ((eventTime- SystemClock.elapsedRealtimeNanos() )/100000000L);//time:当前时间
        calendar.setTimeInMillis(time);//设置时间
        return time - beginTime;
    }

    /**
     * 屏幕触摸响应：点击屏幕，设置目的地
     * 获取触摸点的坐标，并根据坐标移动光标
     * @param v 触摸监听的视图（View）
     * @param event 监听到的事件信息
     * @return 响应
     */
    @Override
    public boolean onTouch(View v, MotionEvent event){
        switch (event.getAction()){
            /**
             * 点击的开始位置
             */
            case MotionEvent.ACTION_DOWN:
//                Log.d(TAG,"起始位置："+event.getX()+"    "+event.getY());
                ObjectAnimator movingX_3 = ObjectAnimator.ofFloat(location,"translationX", event.getX()-20);
                ObjectAnimator movingY_3 = ObjectAnimator.ofFloat(location,"translationY", event.getY()-80);
                AnimatorSet animatorSet_3 = new AnimatorSet();
                animatorSet_3.play(movingY_3).with(movingX_3);
                animatorSet_3.setDuration(1000);
                animatorSet_3.start();
                break;
            /**
             * 触屏实时位置
             */
//            case MotionEvent.ACTION_MOVE:
////               Log.d(TAG,"实时位置："+event.getX()+"    "+event.getY());
//                ObjectAnimator movingX_2 = ObjectAnimator.ofFloat(location,"translationX", event.getX()-20);
//                ObjectAnimator movingY_2 = ObjectAnimator.ofFloat(location,"translationY", event.getY()-80);
//                AnimatorSet animatorSet_2 = new AnimatorSet();
//                animatorSet_2.play(movingY_2).with(movingX_2);
//                animatorSet_2.setDuration(1000);
//                animatorSet_2.start();
//                break;
            /**
             * 离开屏幕的位置
             */
            case MotionEvent.ACTION_UP:
//                Log.d(TAG,"\n------结束位置："+event.getX()+"    "+event.getY());
//                Log.d(TAG,"\n------屏幕偏移："+screenMove+"    ");
                if (screenMove < 0) {
                    location_X = event.getX()-20;
                    location_Y = event.getY()-80;
                }else {
                    location_X = event.getX()-20;
                    location_Y = event.getY()-80;
                }
                ObjectAnimator movingX = ObjectAnimator.ofFloat(location,"translationX", location_X);
                ObjectAnimator movingY = ObjectAnimator.ofFloat(location,"translationY", location_Y);
                AnimatorSet animatorSet = new AnimatorSet();
                animatorSet.play(movingY).with(movingX);
                animatorSet.setDuration(1000);
                animatorSet.start();
                Toast.makeText(MainActivity.this,
                        "已标记目的地，请跟随指示前往（绿线）",Toast.LENGTH_SHORT).show();
                if (screenMove < 0)
                    myView.setDestination(event.getX()+15 + screenMove,event.getY()-25);
                else
                    myView.setDestination(event.getX()+15,event.getY()-25);
//                myView.invalidate();
                myView.setSetDestination(true);
                break;
            default:
                break;
        }
        /**
         *  注意返回值
         *  true：view继续响应Touch操作；
         *  false：view不再响应Touch操作，故此处若为false，只能显示起始位置，不能显示实时位置和结束位置
         */

        return true;
    }

    /**
     * Activity for scanning and displaying available BLE devices.
     */
    private BluetoothAdapter bluetoothAdapter;
    private BluetoothLeScanner sBluetoothLeScanner;
    private boolean mScanning;
    private Handler scanHandler = new Handler();

    // Stops scanning after 10 seconds when SCAN_PERIOD = 10000.
    private static final long SCAN_PERIOD = 1000000;

    /**
     * 开启、关闭对BLE设备的扫描
     * @param enable true or false
     */
    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    private void scanLeDevice(final boolean enable) {
        if (enable) {
            // Stops scanning after a pre-defined scan period.
            scanHandler.postDelayed(new Runnable() {
                @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
                @Override
                public void run() {
                    mScanning = false;
//                    mScanning = !mScanning;
                    sBluetoothLeScanner.stopScan(myScanCallback);
                    Log.d("scanLeDevice", "---------Stop Scan-------");
                    Ble_Rssi.setText("已停止扫描");
                }
            }, SCAN_PERIOD);

            mScanning = true;
            sBluetoothLeScanner.startScan(null,mScannerSetting,myScanCallback);
            Log.d("scanLeDevice", "----------Start Scan--------");
            Ble_Rssi.setText("正在扫描...");
        } else {
            mScanning = false;
            Ble_Rssi.setText("已停止扫描");
            sBluetoothLeScanner.stopScan(myScanCallback);
        }
    }

    /**
     * 初始化BLE相关
     */
    private TextView Ble_Rssi;
    public void iBeacon() {
        Ble_ID = (TextView) findViewById(R.id.tv_value7);
        Ble_ID.setMovementMethod(ScrollingMovementMethod.getInstance());
        Ble_Rssi = findViewById(R.id.tv_value8);
        myBeacon = new Beacon();
    }
    /****
     *   广播接收器
     */
    class LocalReceiver extends BroadcastReceiver {

        @Override
        public void onReceive(Context context, Intent intent) {
            Toast.makeText(context, "received local broadcast", Toast.LENGTH_SHORT).show();
        }
    }

    /**
     * 初始化Android设备的蓝牙
     */
    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
    public void initBLE() {

        final BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
        if (bluetoothManager != null) {
            bluetoothAdapter = bluetoothManager.getAdapter();
        }else { Log.d("DeviceScanActivity"," \n\nbluetoothManager.getAdapter() is null !!\n\n");}
        if (!bluetoothAdapter.isEnabled()) {//是否已开启蓝牙
            bluetoothAdapter.enable();
        }
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {//检测当前系统版本是否支持
            sBluetoothLeScanner = bluetoothAdapter.getBluetoothLeScanner();
            Log.d("initBLE", "\n\n-----------\n\nget Bluetooth LeScanner success!\n\n-----------\n\n");
        }else {
            Log.d("initBLE", "\n\n-----------error: get Bluetooth LeScanner failure!!   *return false of" +
                    "Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP* -----------\n\n");
        }
    }

    /**
     * 源于 Android 蓝牙驱动包：android.bluetooth.le
     * 在发现 LE 蓝牙设备时自动回调,对扫描信息进行处理
     *
     * 重写：
     * 判断是否发现 Beacon 设备
     * 若发现新设备则存入历史记录，否则 更新已有设备信息
     * 打印已发现的 Beacon 设备信息
     */
    private ScanCallback myScanCallback = new ScanCallback() {
        @Override
        public void onScanResult(int callbackType, final ScanResult result) {
//            Log.d("myScanCallback", "\n------------发现 BLE 设备-----------------");
            runOnUiThread(new Runnable() {
                @RequiresApi(api = Build.VERSION_CODES.O)
                @Override
                public void run() {
//                    String newBeacon = Objects.requireNonNull(result.getScanRecord()).getDeviceName(); //得到设备名称
//                    int newRssi = Objects.requireNonNull(result.getRssi());
//                    boolean OE = Objects.requireNonNull(newBeacon).startsWith("OE");//是否是OE beacon
                    String newBeacon = Objects.requireNonNull(result.getScanRecord()).getDeviceName(); //得到设备名称
                    if (newBeacon != null) {
                        int newRssi = result.getRssi();
                        boolean OE = newBeacon.startsWith("OE Beacon");//是否是OE beacon
//                        OE = newBeacon.endsWith("-1");
                        if (OE) {
//                            Ble_ID.append("----"+newBeacon+"-----\n");
//                            Ble_ID.append(" - " + newRssi+"\n");
//                            Log.d("myScanCallback", "\n     发现蓝牙！:" + newBeacon+"\n");
                            int index = beaconList.indexOf(newBeacon);
                            if (index == -1) {//第一次发现该设备则添加进Beacon记录
                                beaconList.append(newBeacon);
                                myBeacon.setName(lastBeacon, newBeacon);
                                myBeacon.setRssi(lastBeacon, newRssi);
                                lastBeacon += 1;
                            } else {
                                index = (index/11);//识别Beacon，与已存的Beacon库进行对比
//                                rssitest[index] = newRssi;
//                                int filterRssi = kalman_1.movingGaussianFilter(newRssi);//弃用高斯滤波
                                int kalmanRssi = selectKalmanFilter(index, newRssi);//只用卡尔曼滤波
                                myBeacon.setRssi(index, kalmanRssi);
                            }
                            Ble_ID.setText("");
                            for (int i = 0; i < lastBeacon; i++) {
//                                Ble_ID.append("---------------------\n");
                                if (myBeacon.getRssi(i) > -65){//是否有Beacon设备在附近
                                    Ble_ID.append(i + "   "+myBeacon.getName(i) + "  Rssi:" + myBeacon.getRssi(i));//打印扫描信息
                                    float Ble_distance = distance(myBeacon.getRssi(i));//计算距离，保留到mm
                                    if (Ble_distance < 1.5 ){
                                        int beaconNum = Integer.valueOf(myBeacon.getName(i).substring(10));//String 转 int,获取当前邻近Beacon标识
                                        reSetLoction(beaconNum);
                                    }
                                }
//                                Ble_ID.append(myBeacon.getName(i) + "  Rssi:" + myBeacon.getRssi(i));//打印扫描信息
//                                String d = distance(myBeacon.getRssi(i));//计算距离，保留到mm
//                                Ble_ID.append("距离：" + d + "\n");

//                                if ()
                            }
                        }
                    }
                }
            });
        }
    };

    /**
     * 根据 RSSI 计算 Beacon 与 Android 设备的距离
     *
     * 标记是否已离开Beacon信标范围（distance>3米）：
     *      若是，则重新接受Beacon对定位坐标的更新
     *      若否，则判断未离开Beacon设备信号范围，故不由Beacon更新坐标
     * 避免在Beacon附近频繁重置坐标，无法离开Beacon信号范围
     * @param rssi 接受到的 Beacon RSSI值
     * @return 距离，单位：米
     */
    private float distance(int rssi){  //RSSI = A - 10*n*lg(d)
        double Rssi = Math.abs(rssi);
        double power = (Rssi - 52) / (10.0 * 1.7);// n 原为3.3
        //93=10米    60=1米
        float distance = (float) Math.pow(10, power);
        DecimalFormat decimalFormat = new DecimalFormat("0.0000");
//        String d = decimalFormat.format(distance);
        Ble_ID.append("\n距离："+ distance +"米\n");//返回6位有效数字
        if (distance > 3)
            resetLocationFlag = true;

        return distance;
    }

    private void reSetLoction(int num){
        if (resetLocationFlag){
            moveArrow[0] = myBeacon.getBeacon_X(num-1);
            moveArrow[1] = myBeacon.getBeacon_Y(num-1);
            myView.setLastStepX(myBeacon.getBeacon_X(num-1));
            myView.setLastStepY(myBeacon.getBeacon_Y(num-1));
            Log.d(TAG,"\n reset location X :"+myView.getLastStepX()+"\n");

            resetLocationFlag = false;
        }
    }

    private void intiKalmanFilter(){
        kalman_1 = new Kalman(9.0,100.0);//预测误差的方差,噪声误差的方差
        kalman_2 = new Kalman(9.0,100.0);
        kalman_3 = new Kalman(9.0,100.0);
        kalman_4 = new Kalman(9.0,100.0);

    }

    private int selectKalmanFilter(int index, int newRssi){
        int kalmanRssi = 0;
        switch (index){
            case 0: kalmanRssi = (int) kalman_1.KalmanFilter(newRssi);break;
            case 1: kalmanRssi = (int) kalman_2.KalmanFilter(newRssi);break;
            case 2: kalmanRssi = (int) kalman_3.KalmanFilter(newRssi);break;
            case 3: kalmanRssi = (int) kalman_4.KalmanFilter(newRssi);break;
        }
        return kalmanRssi;
    }
    /**
     * 检测是否拥有权限
     */
    public void getBlePermissionFromSys() {
        if (Build.VERSION.SDK_INT >= 23) {
            int REQUEST_CODE_CONTACT = 102;
            String[] permissions = {Manifest.permission.ACCESS_COARSE_LOCATION};
            //验证是否许可权限
            for (String str : permissions) {
                if (this.checkSelfPermission(str) != PackageManager.PERMISSION_GRANTED) {
                    //申请权限
                    this.requestPermissions(permissions, REQUEST_CODE_CONTACT);
                    return;
                }
            }
        }//endregion
    }

    /********   切换Fragment   闲置    *********
     *未启用
     * @param number
     */
    public void onSectionAttached(int number) {
        switch (number) {
            case 1:

                break;
        }
    }

}

